<script setup>
import {computed, ref, onMounted} from 'vue'
import {ScanHistory, ScanLiveHosts, ScanLogSSE, ScanStatus, ScanVulInfo, StartScan, StopScan} from "../net/api.js";
import {useRouter} from "vue-router";
import {MoreInfoData} from "../store/page.js";

const router = useRouter()

// 展示上次扫描逻辑
const lastSearchResult = ref(0)
const lastSearchDate = ref('23-2')
let lastHistory = null


onMounted(async () => {
  let data = await ScanHistory()
  if (data.length === 0) {
    return
  }

  let history = data[data.length-1]
  lastHistory = history
  let vulData = await ScanVulInfo({
    taskid: history.taskid
  })

  let [year,mouth, day] = history.taskStartTime.split('T')[0].split('-')

  lastSearchResult.value = 0
  lastSearchDate.value = `${mouth}-${day}`

  vulData.forEach(value => {
    lastSearchResult.value += value.vul.length
  })


})


async function toInfo() {
  let [year,mouth, day] = lastHistory.taskStartTime.split('T')[0].split('-')

  /**@type {VulInfoData}*/
  let oneTaskVulData = {ipScan: [], searchIp: lastHistory.ip, date: `${mouth}-${day}`}

  let portData = await ScanLiveHosts({
    taskid: lastHistory.taskid
  })

  portData.forEach(value => {
    oneTaskVulData.ipScan.push({
      ip: value.ip,
      ports: value.ports,
      vul: []
    })
  })

  let vulDataResp = await ScanVulInfo({
    taskid: lastHistory.taskid
  })

  vulDataResp.forEach(value => {
    let index = oneTaskVulData.ipScan.findIndex(v => v.ip === value.ip)
    if (index === -1)  {
      oneTaskVulData.ipScan.push({
        ip: value.ip,
        vul: value.vul,
        ports: []
      })
      return
    }

    oneTaskVulData.ipScan[index].vul = value.vul
  })

  MoreInfoData.data = oneTaskVulData
  await router.push({
    path: '/more/info'
  })
}

// 扫描中逻辑
const starting = ref(false)
const timestamp = ref(0)
const time = computed(() => {
  if (timestamp.value === 0) {
    return '00:00:00'
  }
  // 将总秒数转换为时、分、秒
  const hours = Math.floor(timestamp.value / 3600);
  const minutes = Math.floor((timestamp.value % 3600) / 60);
  const remainingSeconds = timestamp.value % 60;

  // 将时、分、秒格式化为 "00:00:00" 的格式
  return (hours < 10 ? '0' : '') + hours + ':' +
      (minutes < 10 ? '0' : '') + minutes + ':' +
      (remainingSeconds < 10 ? '0' : '') + remainingSeconds;
})
const inputIP = ref('')

/**
 * @typedef {
 *   {
 *     id: string
 *     data: string
 *   }
 * } RowData
 * */

/**@type { import('vue').Ref<RowData[]> }*/
const rowData = ref([])

/**@type {EventSource | null}*/
let sse = null
/**@type {import('vue').Ref<HTMLUListElement>}*/
const scanListUL = ref()



function control() {

  const regex = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}(\/(([1-2]\d)|(3[0-2])|(\d)))?$/;
  if(inputIP.value == '') 
  {
    ElMessage.error('IP地址不能为空')
    return

  }
  else if(!regex.test(inputIP.value)){
     ElMessage.error('请填写正确的IP地址')
      return
  }

  if (starting.value) {
    cancel()
  } else {
    start()
  }
}

async function lookupStatus() {
  let status = await ScanStatus()
  if (status === "1" || starting.value === false) {
    starting.value = false
    return
  }
  setTimeout(lookupStatus, 2000)
}

async function start() {
  starting.value = true
  try {
    await StartScan({
      host: inputIP.value
    })
    rowData.value = []
    startSSE()
    startTime()
    lookupStatus()
  } catch (e) {
    sse?.close()
  }
}

async function cancel() {
  starting.value = false
  try {
    await StopScan()
    sse?.close()
  } catch (e) {

  }
}

function startSSE() {
  sse = ScanLogSSE()
  let id = 1
  /**@param {MessageEvent} ev*/
  sse.onmessage = (ev) => {
    id++
    rowData.value.push({
      id: id.toString(),
      data: ev.data
    })
    requestAnimationFrame(() => {
      scanListUL.value.scroll({
        top: scanListUL.value.scrollHeight
      })
    })
  }
}

function startTime() {
  setTimeout(() => {
    timestamp.value++
    if (!starting.value) {
      timestamp.value = 0
      return
    }
    startTime()
  }, 1000)

}

</script>

<template>

<div class="scan-root">
  <div v-if="!starting" class="scan-header">
    <div>
      <img src="../assets/images/search.png" style="max-width: 100%;" >
    </div>
    <div class="info-text">
      {{ "上次搜索发现了" + lastSearchResult + "个漏洞" }}
    </div>
    <div></div>
    <div class="date-text">
      <div>{{ lastSearchDate }}</div>
      <div></div>
      <div class="scan-to-info" @click="toInfo">查看详情</div>
    </div>
  </div>
  <div v-if="starting" class="scanning-header">
    <div>
      <img src="../assets/images/search.png" style="max-width: 100%;" >
      扫描中
    </div>
    <div class="info-text">
      {{ inputIP }}
    </div>
    <div class="date-text">
      <div></div>
      <div></div>
      <div>{{ time }}</div>
    </div>
  </div>


  <div class="search-content">
    <div style="height: 20%"></div>
    <div v-if="!starting" style="font-size: 30px; color: gray">输入IP扫描漏洞</div>
    <div style="height: 2%"></div>
    <div  class="input-log"
      :class="{
      inputheight: !starting,
      showlog: starting
      }"
    >
      <div v-if="starting" class="scan-row-data-content" >
        <div style="width: 100%; height: 90%; display: flex; flex-direction: column; align-items: center; overflow: hidden">
          <ul ref="scanListUL" class="scan-infinite-list" style="overflow: auto; width: 95%; height: 100%">
            <li v-for="data in rowData" :key="data.id">
              {{ data.data }}
            </li>
          </ul>

        </div>

      </div>
<!--      展开-->
      <div v-if="!starting" style="height: 100%; width: 100%">
        <input v-model="inputIP" type="text" style="width: 100%; height: 100%; "  />
      </div>

    </div>
    <div class="searchButton" @click="control">
      {{ !starting ? "扫描" : "取消" }}
    </div>
  </div>
</div>

</template>

<style scoped>

.scan-root {
  height: 100%;
  width: 100%;
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 20% 80%;
  background-color: #DFE1EE;
}

.scan-infinite-list {
  height: 100%;
  padding: 0;
  margin: 0;
}

.scan-header {
  width: 100%;
  height: 100%;
  background-color: #F6F5FB;
  box-shadow: #737578 0 2px 3px;
  display: grid;
  grid-template-columns: 20% 45% 20% 10%;
  grid-template-rows: 1fr;
  place-items: center;
}

.info-text {
  font-size: 30px;
  color: grey;
}

.date-text {
  height: 80%;
  font-size: 18px;
  color: gray;
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 20% 1fr 20%;
  padding-top: 10%;
  padding-bottom: 10%;
  text-align: end;
}

.search-content {
  display: flex;
  height: 100%;
  width: 100%;
  flex-direction: column;
  place-items: center;
  overflow: hidden;
}

.searchButton {
  cursor: pointer;
  border-radius: 50px;
  color: white;
  background: linear-gradient(to right,#12A8FC, #60AAEC);
  width: 15%;
  height: 8%;
  margin-top: 3%;
  display: grid;
  place-items: center;
  box-shadow: 1px 2px gray;
}

.searchButton:hover {
  cursor: pointer;
  border-radius: 50px;
  color: white;
  background: linear-gradient(to right, #0ca1f1, #4ea2ee);
  width: 15%;
  height: 8%;
  display: grid;
  place-items: center;
  box-shadow: 1px 2px gray;
}

.input-log {
  transition:
      width 0.5s,
      height 0.5s;
}

.showlog {
  height: 260px;
  width: 80%;
}

.inputheight {
  height: 7%;
  width: 50%;
}

.scanning-header {
  width: 100%;
  height: 100%;
  background-color: #F6F5FB;
  box-shadow: #737578 0 2px 3px;
  display: grid;
  grid-template-columns: 27% 53% 20%;
  grid-template-rows: 1fr;
  place-items: center;
}

.scan-row-data-content {
  background-color: white;
  width: 100%;
  height: 100%;
  border-radius: 15px;
}

.scan-to-info {
  cursor: pointer;
}

.scan-to-info:hover {
  color: #4ea2ee;
}

</style>